"""
MythBoxLink - http://mythboxlink.googlecode.com
(c) 2011 Jared Sutton <jpsutton@gmail.com>

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License, version 2 as
published by the Free Software Foundation. 

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
"""

import sqlite3, sys
import MythBoxLinkUtils as utils
from MythBoxLinkSettings import settings
from tempfile import mkdtemp
from os.path import join as joinPath
from os.path import dirname
from os import rmdir
from os import unlink as deleteFile
from thetvdbapi import TheTVDB
from Queue import PriorityQueue

class LocalTVDB:
  def __init__ (self):
    self.dbConn = None
    self.dbFilename = joinPath(mkdtemp(), "episodeDB.sqlite")
    self.thetvdb = TheTVDB("01878B63F873C550")
    self.createEpisodeDB()
    self.retrievedShows = list()
    self.errorShows = list()

  def getEpisodeDbCursor (self):
    return self.dbConn.cursor()

  def createEpisodeDB (self):
    self.dbConn = sqlite3.connect(self.dbFilename)
    edbCursor = self.getEpisodeDbCursor()
    edbCursor.execute("CREATE TABLE episodes (id INTEGER PRIMARY KEY, title TEXT, subtitle TEXT, orig_air_date TEXT, season INTEGER, episode INTEGER, already_used NUMERIC, absolute_number TEXT, production_code TEXT);")
    self.dbConn.commit()

  def deleteEpisodeDB (self):
    self.dbConn.close()
    deleteFile(self.dbFilename)
    rmdir(dirname(self.dbFilename))

  def getEpisodeData (self, searchTitle):
    if searchTitle in self.retrievedShows:
      return True
    elif searchTitle in self.errorShows:
      return False

    try:
      edbCursor = self.getEpisodeDbCursor()
      episodeList = self.thetvdb.get_show_and_episodes(self.thetvdb.get_best_matching_show(searchTitle)[0])[1]

      for episode in episodeList:
        edbCursor.execute("INSERT INTO episodes VALUES (NULL, ?, ?, ?, ?, ?, 0, ?, ?)", (searchTitle, episode.name, episode.first_aired, episode.season_number, episode.episode_number, episode.absolute_number, episode.production_code))

      self.dbConn.commit()
      self.retrievedShows.append(searchTitle)
    except:
      print(sys.exc_info())
      self.errorShows.append(searchTitle)
      return False

    return True

  def markEpisodeUsed (self, episodeID):
    upCursor = self.getEpisodeDbCursor()
    upCursor.execute("UPDATE episodes SET already_used = 1 WHERE id = ?;", (episodeID, ))
    self.dbConn.commit()

  def searchByAbsEpNum (self, epData):
    (epFirstAired, epTitle, epSubTitle, absEpNum) = epData

    if absEpNum == "":
      return None

    edbCursor = self.getEpisodeDbCursor()
    results = edbCursor.execute("SELECT * FROM episodes WHERE (absolute_number = ? OR production_code = ?) AND already_used != 1;", (absEpNum, absEpNum)).fetchall()

    if len(results) > 0:
      self.markEpisodeUsed(results[0][0])
      return utils.formatFileName(results[0], epTitle)
    else:
      return None
      

  def searchByAirDateAndSubtitle (self, epData):
    stringMatchQueue = PriorityQueue()
    (epFirstAired, epTitle, epSubTitle, absEpNum) = epData
    edbCursor = self.getEpisodeDbCursor()
    results = edbCursor.execute("SELECT * FROM episodes WHERE orig_air_date = ? AND title = ? AND already_used != 1;", (epFirstAired, epTitle)).fetchall()

    # if only one show aired on that date, then no need to go any further
    if len(results) == 1:
      self.markEpisodeUsed(results[0][0])
      return utils.formatFileName(results[0], epTitle)

    # there must have been more than one on that date, so do a closest subtitle match on that set
    for item in map(lambda x: (utils.levenshtein(x[2], epSubTitle), x), results):
      # a Levenshtein value of 0 means exact string match
      if item[0] == 0:
        self.markEpisodeUsed(item[1][0])
        return utils.formatFileName(item[1], epTitle)
      else:
        stringMatchQueue.put(item)

    if not stringMatchQueue.empty():
      result = stringMatchQueue.get()
      if settings.debug and result[0] >= 5:
        print "performed airdate+subtitle match with value of %d" % result[0]
        print "  -> thetvdb subtitle was \"%s\"" % result[1][2]
        print "  -> mythtv  subtitle was \"%s\"" % epSubTitle
      self.markEpisodeUsed(result[1][0])
      return utils.formatFileName(result[1], epTitle)
    else:
      return None

  def searchBySubtitle (self, epData):
    stringMatchQueue = PriorityQueue()
    (epFirstAired, epTitle, epSubTitle, absEpNum) = epData
    edbCursor = self.getEpisodeDbCursor()
    results = edbCursor.execute("SELECT * FROM episodes WHERE title = ? AND already_used != 1;", (epTitle,)).fetchall()

    for item in map(lambda x: (utils.levenshtein(x[2], epSubTitle), x), results):
      # a Levenshtein value of 0 means exact string match
      if item[0] == 0:
        self.markEpisodeUsed(item[1][0])
        return utils.formatFileName(item[1], epTitle)
      else:
        stringMatchQueue.put(item)

    if not stringMatchQueue.empty():
      result = stringMatchQueue.get()
      if settings.debug and result[0] >= 5:
        print "performed subtitle match with value of %d" % result[0]
        print "  -> thetvdb subtitle was \"%s\"" % result[1][2]
        print "  -> mythtv  subtitle was \"%s\"" % epSubTitle

      if result[0] > 10:
        return None

      self.markEpisodeUsed(result[1][0])
      return utils.formatFileName(result[1], epTitle)
    else:
      return None
